package com.pai4j.connect.messagequeue.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.core.RedisTemplate;

import java.nio.charset.StandardCharsets;

/**
 * Redis消息处理工具类
 * 提供统一的消息反序列化和验证功能
 *
 * @author: CYM-pai
 * @date: 2025/09/21
 */
@Slf4j
public class RedisMessageUtil {

    /**
     * 安全地反序列化Redis消息
     * 处理可能存在的编码问题和无效字符
     *
     * @param message Redis消息对象
     * @param redisTemplate Redis模板
     * @return 清理后的消息字符串，如果无法处理则返回null
     */
    public static String safeDeserializeMessage(Message message, RedisTemplate<?, ?> redisTemplate) {
        if (message == null || message.getBody() == null) {
            log.warn("接收到空的Redis消息");
            return null;
        }

        try {
            // 首先尝试使用RedisTemplate的字符串序列化器
            String messageStr = (String) redisTemplate.getStringSerializer().deserialize(message.getBody());
            
            if (StringUtils.isBlank(messageStr)) {
                log.warn("Redis消息反序列化后为空");
                return null;
            }

            // 验证和清理消息
            String cleanedMessage = validateAndCleanMessage(messageStr);
            if (cleanedMessage == null) {
                // 如果字符串序列化器失败，尝试直接使用UTF-8解码
                log.debug("尝试使用UTF-8直接解码Redis消息");
                messageStr = new String(message.getBody(), StandardCharsets.UTF_8);
                cleanedMessage = validateAndCleanMessage(messageStr);
            }

            return cleanedMessage;

        } catch (Exception e) {
            log.error("Redis消息反序列化失败: {}", e.getMessage());
            
            // 最后的尝试：直接使用UTF-8解码
            try {
                String messageStr = new String(message.getBody(), StandardCharsets.UTF_8);
                return validateAndCleanMessage(messageStr);
            } catch (Exception fallbackException) {
                log.error("Redis消息UTF-8解码也失败: {}", fallbackException.getMessage());
                return null;
            }
        }
    }

    /**
     * 安全地反序列化Redis频道名称
     *
     * @param message Redis消息对象
     * @param redisTemplate Redis模板
     * @return 频道名称字符串
     */
    public static String safeDeserializeChannel(Message message, RedisTemplate<?, ?> redisTemplate) {
        if (message == null || message.getChannel() == null) {
            return "unknown";
        }

        try {
            return (String) redisTemplate.getStringSerializer().deserialize(message.getChannel());
        } catch (Exception e) {
            log.warn("Redis频道名称反序列化失败，使用UTF-8解码: {}", e.getMessage());
            try {
                return new String(message.getChannel(), StandardCharsets.UTF_8);
            } catch (Exception fallbackException) {
                log.error("Redis频道名称UTF-8解码失败: {}", fallbackException.getMessage());
                return "unknown";
            }
        }
    }

    /**
     * 验证和清理消息内容
     * 处理可能存在的编码问题和无效字符
     *
     * @param messageStr 原始消息字符串
     * @return 清理后的有效JSON字符串，如果无法修复则返回null
     */
    private static String validateAndCleanMessage(String messageStr) {
        if (StringUtils.isBlank(messageStr)) {
            return null;
        }

        try {
            // 首先尝试直接验证，如果成功则直接返回
            if (isValidJson(messageStr)) {
                return messageStr;
            }

            // 如果直接验证失败，尝试清理消息
            String cleanedMessage = cleanInvalidCharacters(messageStr);
            if (isValidJson(cleanedMessage)) {
                log.debug("消息清理成功，原始消息包含无效字符");
                return cleanedMessage;
            }

            // 如果清理后仍然无效，记录详细错误信息
            log.warn("消息验证失败，无法解析为有效JSON: {}", 
                    messageStr.length() > 200 ? messageStr.substring(0, 200) + "..." : messageStr);
            return null;

        } catch (Exception e) {
            log.error("消息验证过程中发生异常: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 检查字符串是否为有效的JSON格式
     *
     * @param jsonStr 待检查的字符串
     * @return true如果是有效JSON，否则false
     */
    private static boolean isValidJson(String jsonStr) {
        try {
            // 使用Jackson ObjectMapper快速验证JSON格式
            com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
            mapper.readTree(jsonStr);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 清理字符串中的无效字符
     * 移除可能导致JSON解析失败的控制字符和非打印字符
     *
     * @param messageStr 原始消息字符串
     * @return 清理后的字符串
     */
    private static String cleanInvalidCharacters(String messageStr) {
        if (StringUtils.isBlank(messageStr)) {
            return messageStr;
        }

        // 移除字符串开头的无效字符（通常是BOM或其他控制字符）
        String cleaned = messageStr.replaceAll("^[\\x00-\\x1F\\x7F\\uFFFD]+", "");
        
        // 移除字符串中间的控制字符，但保留必要的空白字符（空格、制表符、换行符）
        cleaned = cleaned.replaceAll("[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F\\uFFFD]", "");
        
        // 查找第一个 '{' 字符的位置，JSON应该从这里开始
        int jsonStart = cleaned.indexOf('{');
        if (jsonStart > 0) {
            cleaned = cleaned.substring(jsonStart);
            log.debug("检测到JSON前存在无效字符，已清理. 清理后长度: {}", cleaned.length());
        }
        
        return cleaned.trim();
    }

    /**
     * 验证消息格式是否包含基本的JSON结构和必要字段
     *
     * @param message 消息字符串
     * @param requiredFields 必需的字段名称数组
     * @return true如果格式有效，否则false
     */
    public static boolean isValidMessageFormat(String message, String... requiredFields) {
        if (StringUtils.isBlank(message)) {
            return false;
        }

        // 检查是否包含基本的JSON结构
        String trimmed = message.trim();
        if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
            return false;
        }

        // 检查是否包含必要的字段
        if (requiredFields != null) {
            for (String field : requiredFields) {
                if (!trimmed.contains("\"" + field + "\"")) {
                    return false;
                }
            }
        }

        return true;
    }
}
